#include "board.h"
#include "LoRaMac-api-v3.h"
#include "join-info.h"

/*!
 * Defines number of channel mask bit for each variable
 */
#define MASK_BIT_NB 16

/*!
 * Defines join information sava flag
 */
#define HAS_JOIN_INFO   ((uint32_t)0xaaaaaaaa)

void Set_join_info(Join_info_t *Join_info)
{
    MibRequestConfirm_t mibSet;
    uint8_t i;

    if(Join_info == NULL)
        return ;

    // Set NetID
    mibSet.Type = MIB_NET_ID;
    mibSet.Param.NetID = Join_info->NetID;
    LoRaMacMibSetRequestConfirm( &mibSet );

    // Set DevAddr
    mibSet.Type = MIB_DEV_ADDR;
    mibSet.Param.DevAddr = Join_info->DevAddr;
    LoRaMacMibSetRequestConfirm( &mibSet );

    // Set NwkSKey
    mibSet.Type = MIB_NWK_SKEY;
    mibSet.Param.NwkSKey = Join_info->NwkSKey;
    LoRaMacMibSetRequestConfirm( &mibSet );

    // Set AppSKey
    mibSet.Type = MIB_APP_SKEY;
    mibSet.Param.AppSKey = Join_info->AppSKey;
    LoRaMacMibSetRequestConfirm( &mibSet );

	// Set channel list
    for(i = 3; i < MAX_SAVE_CHANNELS; i++)
    {
        LoRaMacChannelAdd(Join_info->Channel_index[i], Join_info->ChannelList[i]);
    }

    // Set fcnt
    mibSet.Type = MIB_UPLINK_COUNTER;
    mibSet.Param.UpLinkCounter = Join_info->Fcnt;
    LoRaMacMibSetRequestConfirm( &mibSet );

    // Set receivedelay
    mibSet.Type = MIB_RECEIVE_DELAY_1;
    mibSet.Param.ReceiveDelay1 = Join_info->ReceiveDelay1;
    LoRaMacMibSetRequestConfirm( &mibSet );
    mibSet.Type = MIB_RECEIVE_DELAY_2;
    mibSet.Param.ReceiveDelay1 = Join_info->ReceiveDelay2;
    LoRaMacMibSetRequestConfirm( &mibSet );

    mibSet.Type = MIB_NETWORK_JOINED;
    mibSet.Param.IsNetworkJoined = true;
    LoRaMacMibSetRequestConfirm( &mibSet );

}

void Get_join_info(Join_info_t *Join_info)
{
    MibRequestConfirm_t mibGet;
    uint8_t i = 0;
    uint16_t mask[LORA_MAX_NB_CHANNELS/MASK_BIT_NB];
    uint8_t channel_count = 0;

    if(Join_info == NULL)
        return ;

    // Get NetID
    mibGet.Type = MIB_NET_ID;
    LoRaMacMibGetRequestConfirm(&mibGet);
    Join_info->NetID = mibGet.Param.NetID;

    // Get DevAddr
    mibGet.Type = MIB_DEV_ADDR;
    LoRaMacMibGetRequestConfirm(&mibGet);
    Join_info->DevAddr = mibGet.Param.DevAddr;

    // Get NwkSKey
    mibGet.Type = MIB_NWK_SKEY;
    LoRaMacMibGetRequestConfirm(&mibGet);
    memcpy1(Join_info->NwkSKey, (const uint8_t *)mibGet.Param.NwkSKey, 16);

    // Get AppSKey
    mibGet.Type = MIB_APP_SKEY;
    LoRaMacMibGetRequestConfirm(&mibGet);
    memcpy1(Join_info->AppSKey, (const uint8_t *)mibGet.Param.AppSKey, 16);

    // Get receivedelay1
    mibGet.Type = MIB_RECEIVE_DELAY_1;
    LoRaMacMibGetRequestConfirm(&mibGet);
    Join_info->ReceiveDelay1 = mibGet.Param.ReceiveDelay1;

    // Get receivedelay2
    mibGet.Type = MIB_RECEIVE_DELAY_2;
    LoRaMacMibGetRequestConfirm(&mibGet);
    Join_info->ReceiveDelay2 = mibGet.Param.ReceiveDelay2;

    // Get channel mask
    mibGet.Type = MIB_CHANNELS_MASK;
    LoRaMacMibGetRequestConfirm(&mibGet);
    memcpy1((uint8_t *)mask, (uint8_t *)mibGet.Param.ChannelsDefaultMask, sizeof(mask));

    // Recode index of channel mask
    while(channel_count<MAX_SAVE_CHANNELS && i<LORA_MAX_NB_CHANNELS)
    {
        if((mask[i/MASK_BIT_NB] >> (i%MASK_BIT_NB)) & 0x0001)
        {
            Join_info->Channel_index[channel_count++] = i;
        }
        i++;
    }

    // Get used channels
    mibGet.Type = MIB_CHANNELS;
    LoRaMacMibGetRequestConfirm(&mibGet);
    for(i = 0; i < MAX_SAVE_CHANNELS; i++)
    {
        memcpy1((uint8_t *)&Join_info->ChannelList[i], (const uint8_t *)&mibGet.Param.ChannelList[Join_info->Channel_index[i]], sizeof(ChannelParams_t)); 
    }

    // Get fcnt
    mibGet.Type = MIB_UPLINK_COUNTER;
    LoRaMacMibGetRequestConfirm(&mibGet);
    Join_info->Fcnt = mibGet.Param.UpLinkCounter;
}

void Store_join_info(Join_info_store_t *Join_info_store)
{
    Join_info_store->Store_flg = HAS_JOIN_INFO;
    Write_flash_data((uint8_t *)Join_info_store, sizeof(Join_info_store_t), E_START_FLASH_ADDR_JOIN_INFO);
}

bool Read_join_info(Join_info_store_t *Join_info_store)
{
    Read_flash_data((uint8_t *)Join_info_store, sizeof(Join_info_store_t), E_START_FLASH_ADDR_JOIN_INFO);
    if(Join_info_store->Store_flg == HAS_JOIN_INFO)
    {
        Read_flash_data((uint8_t *)&Join_info_store->JoinInfo.Fcnt, sizeof(uint32_t), E_START_FLASH_ADDR_FCNT);
        return true;
    }
    return false;
}


